const TronWeb = require('tronweb');
import Level from 'level-ts'
import { existsSync, mkdirSync } from 'fs'

import { logger } from '@pkg/logger'
import { Signer } from "@app/signer"
import { Wallet } from "@app/wallet"
import { Poller } from "@app/poller"
import { Worker } from "@app/worker"
import { RpcServer } from "@app/server"
import { Accounts } from "@app/accounts"
import { BalanceManager } from '@app/balances'
import { openConnect } from "@app/storage/conn"

import * as config from '@config/server.json'

async function *iterator(values: any[]) {
    for (let i = 0; i < values.length; i++) {
        yield values[i]
    }
}

(async () => {
    if (!existsSync(config.datadir)) {
        mkdirSync(config.datadir, { recursive: true })
    }

    // 连接数据库
    await openConnect('tronscan')

    // 连接tron节点
    const tronWeb = new TronWeb({
        fullHost: config.fullHost,
        solidityNode: config.solidityNode
    })
    const block = await tronWeb.trx.getCurrentBlock()
    logger.info('current block number: %s', block.block_header.raw_data.number)

    const owner = tronWeb.address.fromPrivateKey(config.hotwallet)
    tronWeb.setAddress(owner)
    logger.info('owner address: %s', owner)

    // 连接trongrid
    const trongrid = new TronWeb({ fullHost: config.trongrid })
    const genesisBlockA = await tronWeb.trx.getBlock(0)
    const genesisBlockB = await trongrid.trx.getBlock(0)
    if (genesisBlockA.blockID !== genesisBlockB.blockID) {
        throw new Error('chain id mismatch')
    }

    // 加载本地账号
    const accounts = new Accounts(tronWeb)
    logger.info('load all local accounts, please wait...')
    const count = await accounts.loadAccounts()
    logger.info('load all local accounts done, count: %s', count)

    // 创建余额缓存
    const wallet = new Wallet(tronWeb, accounts, new Signer(trongrid))
    const db = new Level(config.datadir + '/tronscan')

    // 更新缓存数据
    const symbols = wallet.getSymbols()
    const balances = new BalanceManager(wallet, db)
    for (let i = 0; i < symbols.length; i++) {
        const symbol = symbols[i]
        if (symbol !== 'TRX') {
            await wallet.getToken(symbol)
        }
        await balances.updateBalance(owner, symbol)
    }

    // 是否刷新余额
    if (config.reload) {
        logger.info('will reload the balances of all addresses, please wait')
        for await (let address of iterator(wallet.accounts.getAccounts())) {
            for (let i = 0; i < symbols.length; i++) {
                await balances.updateBalance(address, symbols[i])
            }
        }
    }

    // 启动区块轮询器
    const poller = new Poller(wallet, balances)
    poller.startPolling()

    // 启动后台作业
    const worker = new Worker(wallet, balances)
    worker.run()

    // 启动JSON-RPC服务器
    const server = new RpcServer(wallet, balances)
    server.run(config.host, config.port)

})().catch((reason => {
    logger.error(reason)
}))
